/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.amse.grigory.dchess.rules;

import java.util.ArrayList;
import org.amse.grigory.dchess.kernel.*;

/**
 *
 * @author grigory
 */
public class ChessRules extends Rules {

    public ChessRules() {
        super();
    }

    @Override
    public int isWin(Square[][] board, int color) {
        int ans = NOBODY_WIN;
        for (int i = 1; i <= myWidth; ++i) {
            for (int j = 1; j <= myHeight; ++j) {
                for (int k = 1; k <= myWidth; ++k) {
                    for (int l = 1; l <= myWidth; ++l) {
                        if (canMove(board, i, j, k, l, color)) {
                            return ans;
                        }
                    }
                }
            }
        }
        if (isCheck(board, color)) {
            if (color == COLOR_WHITE) {
                return BLACK_WIN;
            } else {
                return WHITE_WIN;
            }
        }
        return DRAW;
    }

    @Override
    public Rules clone() {
        Rules temp = new ChessRules();
        temp.setName(getName());
        temp.setHeight(getHeight());
        temp.setWidth(getWidth());
        int length = getBlackNumber();
        for (int i = 0; i < length; ++i) {
            temp.myBlack.add(myBlack.get(i).clone());
        }
        length = getWhiteNumber();
        for (int i = 0; i < length; ++i) {
            temp.myWhite.add(myWhite.get(i).clone());
        }
        length = getIllegalSquareNumber();
        for (int i = 0; i < length; ++i) {
            temp.addIllegalSquare(getIllegalX(i), getIllegalY(i));
        }
        temp.myFigures=myFigures;

        return temp;
    }

    @Override
    public boolean canMove(Square[][] board, int x, int y, int tx, int ty, int color) {
        if (!canSimplyMove(board, x, y, tx, ty, color)) {
            return false;
        }
        tx--;
        ty--;
        x--;
        y--;
        Square squareTo = board[tx][ty].clone();
        Square squareFrom = board[x][y].clone();
        board[tx][ty].setColor(color);
        board[tx][ty].setFigure(board[x][y].getFigure());
        board[tx][ty].setMoved(false);
        board[x][y].setColor(0);
        board[x][y].setFigure(null);
        if (isCheck(board, color)) {
            board[tx][ty] = squareTo;
            board[x][y] = squareFrom;
            return false;
        }
        board[tx][ty] = squareTo;
        board[x][y] = squareFrom;
        return true;
    }

    @Override
    public boolean makeSMove(Square[][] board, int x, int y, int tx, int ty, int color) {
        if (canMove(board, x, y, tx, ty, color)) {
            if (board[x - 1][y - 1].getFigure().getName().equals("King")) {
                if (Math.abs(tx - x) == 2) {
                    castling(board, x, y, tx, ty, color, new Desk(new BasicChessRules()));
                    return true;
                }
            }
            if (board[x - 1][y - 1].getFigure().canTransform()) {
                if (ty == board[x - 1][y - 1].getFigure().getTransformLine()) {
                    String s = board[x - 1][y - 1].getFigure().getTransformName();
                    Figure temp = getTransformFigure(s, board[x - 1][y - 1].getFigure().getColor());
                    temp.setX(x);
                    temp.setY(y);
                    board[x - 1][y - 1].setFigure(temp);
                }
            }
            tx--;
            ty--;
            x--;
            y--;
            board[tx][ty].setColor(color);
            board[tx][ty].setFigure(board[x][y].getFigure());
            board[tx][ty].setMoved(false);
            board[x][y].setColor(0);
            board[x][y].setFigure(null);
            return true;
        }
        return false;
    }

    @Override
    public boolean start(Square[][] board) {
        int width = myWidth;
        int height = myHeight;

        for (int i = 0; i < width; ++i) {
            for (int j = 0; j < height; ++j) {
                board[i][j] = new Square();
                board[i][j].setMoved(false);
            }
        }
        Figure f;
        int length = getBlackNumber();
        for (int i = 0; i < length; ++i) {
            f = getBlack(i);
            int x = f.getX() - 1;
            int y = f.getY() - 1;
            board[x][y].setFigure(f);
            board[x][y].setColor(COLOR_BLACK);
            board[x][y].setMoved(true);
        }
        length = getWhiteNumber();
        for (int i = 0; i < length; ++i) {
            f = getWhite(i);
            int x = f.getX() - 1;
            int y = f.getY() - 1;
            board[x][y].setFigure(f);
            board[x][y].setColor(COLOR_WHITE);
            board[x][y].setMoved(true);
        }
        length = getIllegalSquareNumber();
        for (int i = 0; i < length; ++i) {
            board[getIllegalX(i)][getIllegalY(i)].setIllegal(1);
        }
        return true;
    }

    @Override
    public String getMessage(Square[][] board, int color) {
        int t = isWin(board, color);
        if (t == DRAW) {
            return "\nDRAW!!!";
        }
        if (t == BLACK_WIN) {
            return "\nCheck and Mate!\nBlack has won!";
        }
        if (t == WHITE_WIN) {
            return "\nCheck and Mate!\nWhite has won!";
        }
        if (isCheck(board, color)) {
            return "\nCheck!";
        }
        return "";
    }

    private boolean canSimplyMove(Square[][] board, int x, int y, int tx, int ty, int color) {
        if (!((x > 0) && (x <= myWidth) && (y > 0) && (y <= myHeight))) {
            return false;
        }
        if (!((tx > 0) && (tx <= myWidth) && (ty > 0) && (ty <= myHeight))) {
            return false;
        }
        x = x - 1;
        y = y - 1;
        tx--;
        ty--;
        Figure figure = board[x][y].getFigure();
        if (figure == null) {
            return false;
        }
        if (board[x][y].getColor() != color) {
            return false;
        }
        if (board[tx][ty].getIllegal() == 1) {
            return false;
        }
        int j = 0;
        int length = 0;
        Figure temp = figure;
        char type = Moves.NOT_A_MOVE;
        int dx = tx - x;
        int dy = ty - y;
        boolean canM = false;
        if (board[tx][ty].getFigure() == null) {
            length = temp.getMovesCount();
            for (int i = 0; i < length; i++) {
                if ((dx == temp.getMoveX(i)) && (dy == temp.getMoveY(i))) {
                    canM = true;
                    type = temp.getMoveType(i);
                    break;
                }
            }
        } else {
            if (board[tx][ty].getColor() == color) {
                return false;
            }
            length = temp.getEatCount();
            for (int i = 0; i < length; i++) {
                if ((dx == temp.getEatX(i)) && (dy == temp.getEatY(i))) {
                    canM = true;
                    type = temp.getEatType(i);
                    break;
                }
            }
        }
        if (!canM) {
            return false;
        }
        switch (type) {
            case Moves.MOVE_SLIDE:
                if (!canSlide(board, x, y, tx, ty, temp)) {
                    canM = false;
                }
                break;
            case Moves.MOVE_FJUMP:
                canM = false;
                break;
            case Moves.MOVE_FSLIDE:
                if (!board[x][y].getMoved()) {
                    canM = false;
                    break;
                }
                if (!canSlide(board, x, y, tx, ty, temp)) {
                    canM = false;
                }
                break;
            case Moves.MOVE_JUMP:
                break;
            case Moves.MOVE_SPECIAL:
                if (board[x][y].getFigure().getName().equals("King")) {
                    canM = canCasstle(board, x, y, tx, ty, color);
                }
                break;
        }

        return canM;
    }

    private final void castling(Square[][] board, int x, int y, int tx, int ty, int color, Desk desk) {
        x--;
        y--;
        tx--;
        ty--;
        int vx = 0;
        int vy = 0;
        if (tx > x) {
            vx = 1;
        }
        if (tx < x) {
            vx = -1;
        }
        if (ty > y) {
            vy = 1;
        }
        if (ty < y) {
            vy = -1;
        }
        int tempx = x + 2 * vx, tempy = y + 2 * vy;
        while ((tempx < myWidth) && (tempy < myHeight) && (tempx > -1) && (tempy > -1)) {
            if (board[tempx][tempy].getFigure() != null) {
                String s = board[tempx][tempy].getFigure().getName();
                if (s.equals("Rook")) {
                    break;
                }
            }
            tempx += vx;
            tempy += vy;
        }
        board[tx][ty].setColor(color);
        board[tx][ty].setFigure(board[x][y].getFigure());
        board[tx][ty].setMoved(false);
        board[x][y].setColor(0);
        board[x][y].setFigure(null);
        desk.addChange(board[tx - vx][ty - vy], tx - vx, ty - vy);
        board[tx - vx][ty - vy].setColor(color);
        board[tx - vx][ty - vy].setFigure(board[tempx][tempy].getFigure());
        board[tx - vx][ty - vy].setMoved(false);
        desk.addChange(board[tempx][tempy], tempx, tempy);
        board[tempx][tempy].setColor(0);
        board[tempx][tempy].setFigure(null);

    }

    private final boolean canCasstle(Square[][] board, int x, int y, int tx, int ty, int color) {
        if (!board[x][y].getMoved()) {
            return false;
        }
        int vx = 0;
        int vy = 0;
        if (tx > x) {
            vx = 1;
        }
        if (tx < x) {
            vx = -1;
        }
        if (ty > y) {
            vy = 1;
        }
        if (ty < y) {
            vy = -1;
        }
        boolean found = false;
        int tempx = x + 2 * vx, tempy = y + 2 * vy;
        if (board[x + vx][y + vy].getFigure() != null) {
            return false;
        }
        while ((tempx < myWidth) && (tempy < myHeight) && (tempx > -1) && (tempy > -1)) {
            if (board[tempx][tempy].getFigure() != null) {
                String s = board[tempx][tempy].getFigure().getName();
                if (!s.equals("Rook")) {
                    return false;
                } else {
                    found = true;
                    break;
                }
            }
            tempx += vx;
            tempy += vy;
        }

        if (!found) {
            return false;
        }
        int i = x, j = y;
        while (i != tx) {
            if (isBeaten(board, i, j, color)) {
                return false;
            }
            i += vx;
            j += vy;

        }
        if (!board[tempx][tempy].getMoved()) {
            return false;
        }
        return true;
    }

    public boolean isBeaten(Square[][] board, int x, int y, int color) {
        for (int i = 0; i < myWidth; ++i) {
            for (int j = 0; j < myHeight; ++j) {
                if ((x != i) || (y != j)) {
                    if (board[x][y].getFigure() != null) {
                        if (board[x][y].getFigure().getName().equals("King")) {
                            if (Math.abs(x - i) > 1) {
                                continue;
                            }
                        }
                    }
                    if (canSimplyMove(board, i + 1, j + 1, x + 1, y + 1, -color)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private final boolean isCheck(Square[][] board, int color) {
        int x = -1;
        int y = -1;
        for (int i = 0; i < myWidth; ++i) {
            for (int j = 0; j < myHeight; ++j) {
                if (board[i][j].getFigure() != null) {
                    if ((board[i][j].getFigure().getName().equals("King")) &&
                            (board[i][j].getColor() == color)) {
                        x = i;
                        y = j;
                        break;
                    }

                }

            }
        }
        if (x == -1) {
            throw new RuntimeException("Where is the KING?!");
        }
        for (int i = 0; i < myWidth; ++i) {
            for (int j = 0; j < myHeight; ++j) {
                if ((x != i) || (y != j)) {
                    if (canSimplyMove(board, i + 1, j + 1, x + 1, y + 1, -color)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private final boolean canSlide(Square[][] board, int x, int y, int tx, int ty, Figure figure) {
        int vx = tx - x;
        int vy = ty - y;
        if ((Math.abs(vx) != Math.abs(vy)) && (vx != 0) && (vy != 0)) {
            return false;
        }
        if (vx > 0) {
            vx = 1;
        }
        if (vx < 0) {
            vx = -1;
        }
        if (vy > 0) {
            vy = 1;
        }
        if (vy < 0) {
            vy = -1;
        }
        int tempx = x + vx;
        int tempy = y + vy;
        while ((tempy != ty) || (tempx != tx)) {
            if (board[tempx][tempy].getFigure() != null) {
                return false;
            }
            if (board[tempx][tempy].getIllegal() == 1) {
                return false;
            }
            tempy += vy;
            tempx += vx;
        }
        return true;
    }

    @Override
    public boolean makeMove(Square[][] board, int x, int y, int tx, int ty, int color, Desk desk) {
        if (canMove(board, x, y, tx, ty, color)) {
            desk.newChange();
            desk.addChange(board[x - 1][y - 1], x - 1, y - 1);
            desk.addChange(board[tx - 1][ty - 1], tx - 1, ty - 1);
            if (board[x - 1][y - 1].getFigure().getName().equals("King")) {
                if (Math.abs(tx - x) == 2) {
                    castling(board, x, y, tx, ty, color, desk);
                    return true;
                }
            }
            if (board[x - 1][y - 1].getFigure().canTransform()) {
                if (ty == board[x - 1][y - 1].getFigure().getTransformLine()) {
                    String s = board[x - 1][y - 1].getFigure().getTransformName();
                    Figure temp = getTransformFigure(s, board[x - 1][y - 1].getFigure().getColor());
                    temp.setX(x);
                    temp.setY(y);
                    board[x - 1][y - 1].setFigure(temp);
                }
            }
            tx--;
            ty--;
            x--;
            y--;
            board[tx][ty].setColor(color);
            board[tx][ty].setFigure(board[x][y].getFigure());
            board[tx][ty].setMoved(false);
            board[x][y].setColor(0);
            board[x][y].setFigure(null);
            return true;
        }
        return false;
    }

    private Figure getTransformFigure(String s, int color) {
        Figure f = myFigures.get(s).clone();
        if (color == Figure.COLOR_BLACK) {
            int length = f.getMovesCount();
            for (int i = 0; i < length; ++i) {
                f.setMoveY(i, -f.getMoveY(i));
            }
            length = f.getEatCount();
            for (int i = 0; i < length; ++i) {
                f.setEatY(i, -f.getEatY(i));
            }
            f.addTransform(myHeight + 1 - f.getTransformLine(), f.getTransformName());
            f.setColor(1);
        }
        return f;
    }
}
